/*
 * SearchServlet.java
 * 
 * Copyright 2012 Xinli Jia
 * 
 * The Servlet handles all requests
 */

package ie.dit.comp.lukejia.fyp.controller;

import ie.dit.comp.lukejia.fyp.model.AbstractOfReview;
import ie.dit.comp.lukejia.fyp.model.WebsiteReview;
import ie.dit.comp.lukejia.fyp.model.Item;
import ie.dit.comp.lukejia.fyp.model.RatingAndReview;
import ie.dit.comp.lukejia.fyp.model.TaggedSentence;
import ie.dit.comp.lukejia.fyp.stanford.Parser;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import com.amazon.advertising.api.AmazonItemSearch;
import com.amazon.advertising.api.GetReviewParser;

/**
 * Servlet implementation class SearchServlet
 */
public class SearchServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private static final String URL_SEARCH_HOME = "/home";
	private static final String URL_SEARCH_HELP = "/help";
	private static final String URL_SEARCH_JSON = "/json";
	private static final String URL_SEARCH_REVIEW = "/review";
	private static Parser parser;
	private static ExecutorService pool;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public SearchServlet() {
		super();
	}

	public class AlchemyAPICallable implements Callable<List<TaggedSentence>> {
		private String text;

		public AlchemyAPICallable(String text) {
			this.text = text;
		}

		public List<TaggedSentence> call() {
			return parser.parsingTextToMap(text);
		}
	}

	@Override
	public void init() throws ServletException {
		super.init();
		System.out.println("init");
		ServletContext application = getServletContext();
		String modulePath = application
				.getRealPath("/models/englishPCFG.ser.gz");
		String swnPath = application
				.getRealPath("/models/SentiWordNet_3.0.0_20120206.txt");
		parser = new Parser(modulePath, swnPath);
		pool = Executors.newFixedThreadPool(2);
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		if (request.getPathInfo().equals(URL_SEARCH_HOME)) {
			request.getRequestDispatcher("/html/index.html").forward(request,
					response);
		} else if (request.getPathInfo().equals(URL_SEARCH_HELP)) {
			request.getRequestDispatcher("/html/help.html").forward(request,
					response);
		} else if (request.getPathInfo().equals(URL_SEARCH_JSON)) {
			String query = request.getParameter("query");
			String category = request.getParameter("category");
			List<Item> items = AmazonItemSearch.searchItem(query, category);

			JSONObject root = new JSONObject();
			JSONArray results = JSONArray.fromObject(items);
			root.put("responseData", results);
			root.put("category", category);
			root.put("responseStatus", 200);

			PrintWriter out = response.getWriter();
			System.out.println(root);
			out.println(root);
		} else if (request.getPathInfo().equals(URL_SEARCH_REVIEW)) {
			String itemTitle = request.getParameter("item");
			String amazonReviewURL = request.getParameter("amazonUrl");
			String category = request.getParameter("category");

			System.out.println(amazonReviewURL);
			RatingAndReview rar = GetReviewParser
					.getAmazonReviewFromURL(amazonReviewURL);
			List<TaggedSentence> group2 = new ArrayList<TaggedSentence>();
			List<String> azReviews = rar.getReviews();
			int[] ratings = rar.getRatings();

			// Calculate overall rating
			int sum = ratings[0] * 5 + ratings[1] * 4 + ratings[2] * 3
					+ ratings[3] * 2 + ratings[4] * 1;
			float rating = ((float) sum)
					/ (float) (ratings[0] + ratings[1] + ratings[2]
							+ ratings[3] + ratings[4]);

			int num = 1;

			for (String str : azReviews) {
				System.out.println("Amazon " + Integer.toString(num++));
				try {
					// Goes first make sure no duplicated result
					Callable<List<TaggedSentence>> callable = new AlchemyAPICallable(
							str);
					Future<List<TaggedSentence>> future = pool.submit(callable);
					group2.addAll(future.get());

				} catch (OutOfMemoryError e) {
					e.printStackTrace();
				} catch (InterruptedException e) {
					e.printStackTrace();
				} catch (ExecutionException e) {
					e.printStackTrace();
				}
				if (num > 3)
					break;
			}

			// Different stream for book or movie
			rating = rating * 2;
			if (category.equals("book")) {
				WebsiteReview gdReviews = null;
				try {
					String asinISBN = request.getParameter("asin");
					String goodReadsReviewURL = "http://www.goodreads.com/api/book_url/"
							+ asinISBN;
					gdReviews = GetReviewParser
							.getGoodreadsReviewFromURL(goodReadsReviewURL);
					float gdRating = gdReviews.getRating();
					if (gdRating > 0) {
						rating = (rating + gdRating * 2) / 2;
					}

					num = 1;
					for (String str : gdReviews.getReviews()) {
						System.out.println("GoodReads "
								+ Integer.toString(num++));
						try {
							// Goes first make sure no duplicated result
							Callable<List<TaggedSentence>> callable = new AlchemyAPICallable(
									str);
							Future<List<TaggedSentence>> future = pool
									.submit(callable);
							group2.addAll(future.get());
						} catch (OutOfMemoryError e) {
							e.printStackTrace();
						}

						// if (num > 2)
						// break;
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			} else if (category.equals("movie")) {
				WebsiteReview imdbReviews = null;
				try {
					String amazonURL = "http://www.amazon.com/gp/product/"
							+ request.getParameter("asin");
					imdbReviews = GetReviewParser
							.getIMDBReviewFromURL(amazonURL);
					float imdbRating = imdbReviews.getRating();
					if (imdbRating > 0) {
						rating = (rating + imdbRating * 2) / 2;
					}

					num = 1;
					for (String str : imdbReviews.getReviews()) {
						System.out.println("Imdb " + Integer.toString(num++));
						try {
							// Goes first make sure no duplicated result
							Callable<List<TaggedSentence>> callable = new AlchemyAPICallable(
									str);
							Future<List<TaggedSentence>> future = pool
									.submit(callable);
							group2.addAll(future.get());
						} catch (OutOfMemoryError e) {
							e.printStackTrace();
						}

						// if (num > 3)
						// break;
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}

			// Solve rounding problem
			float p = (float) Math.pow(10, 1);
			rating = rating * p;
			float tmp = Math.round(rating);
			rating = (float) tmp / p;

			// Get options
			List<AbstractOfReview> absts = rar.getAbstracts();
			AbstractOfReview fav = rar.getFavorableReview();
			AbstractOfReview cri = rar.getCriticalReview();

			JSONObject root = new JSONObject();
			JSONObject responseData = new JSONObject();
			responseData.put("rating", rating);
			responseData.put("title", itemTitle);
			responseData.put("group2", JSONArray.fromObject(group2));
			responseData.put("fav", fav);
			responseData.put("cri", cri);
			responseData.put("group3", JSONArray.fromObject(absts));
			root.put("responseStatus", 200);
			root.put("responseData", responseData);
			response.setCharacterEncoding("UTF-8");

			response.setHeader("Pragma", "no-cache");
			response.setHeader("Cache-Control", "no-cache");
			response.setDateHeader("Expires", 0);

			PrintWriter out = response.getWriter();
			out.println(root);

		} else {
			request.getRequestDispatcher("/jsp/index.jsp").forward(request,
					response);
		}
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
	}

	@Override
	public void destroy() {
		super.destroy();
		pool.shutdown();
	}

}
